Added documentation about how to use the unit test runner.
[adiumx.git] / Plugins / Purple Service / AMPurpleRequestFieldsController.m
blob1d1453deaf2b3f2be5dbe7a45aff9bfc5dc44117
1 //
2 //  AMPurpleRequestFieldsController.m
3 //  Adium
4 //
5 //  Created by Andreas Monitzer on 2007-06-10.
6 //  Copyright 2007 Andreas Monitzer. All rights reserved.
7 //
9 #import "AMPurpleRequestFieldsController.h"
10 #import <AIUtilities/AIImageAdditions.h>
11 #import <AIUtilities/AIStringAdditions.h>
13 @interface WebView (PRIVATE)
14 - (void)setDrawsBackground:(BOOL)flag;
15 - (void)setBackgroundColor:(NSColor *)color;
16 @end
18 @interface AMPurpleRequestField : NSObject {
19     PurpleRequestField *field;
20     CBPurpleAccount *account;
23 - (id)initWithAccount:(CBPurpleAccount*)_account requestField:(PurpleRequestField*)_field;
25 - (NSXMLElement*)xhtml;
26 - (NSString*)key;
28 - (void)applyValue:(NSString*)value;
30 @end
32 @interface AMPurpleRequestFieldString : AMPurpleRequestField {
35 @end
37 @interface AMPurpleRequestFieldInteger : AMPurpleRequestField {
40 @end
42 @interface AMPurpleRequestFieldBoolean : AMPurpleRequestField {
45 @end
47 @interface AMPurpleRequestFieldChoice : AMPurpleRequestField {
50 @end
52 @interface AMPurpleRequestFieldList : AMPurpleRequestField {
55 @end
57 @interface AMPurpleRequestFieldLabel : AMPurpleRequestField {
60 @end
62 @interface AMPurpleRequestFieldAccount : AMPurpleRequestField {
65 @end
67 @interface AMPurpleRequestFieldImage : AMPurpleRequestField {
70 @end
72 @implementation AMPurpleRequestField
74 - (id)initWithAccount:(CBPurpleAccount*)_account requestField:(PurpleRequestField*)_field {
75     if((self = [super init])) {
76         account = _account;
77         field = _field;
78     }
79     return self;
82 - (NSXMLElement*)xhtml {
83         NSXMLElement *result = [NSXMLNode elementWithName:@"div"];
84         
85         [result addAttribute:[NSXMLNode attributeWithName:@"class" stringValue:@"field"]];
86         
87         const char *labelstr = purple_request_field_get_label(field);
88         
89         if(labelstr) {
90                 NSXMLElement *label = [NSXMLNode elementWithName:@"label" stringValue:[NSString stringWithUTF8String:labelstr]];
91                 [label addAttribute:[NSXMLNode attributeWithName:@"for" stringValue:[self key]]];
92                 
93                 [result addChild:[NSXMLNode elementWithName:@"div"
94                                                                                    children:[NSArray arrayWithObject:label]
95                                                                                  attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"label"]]]];
96         }
97         return result;
100 - (NSString*)key {
101     return [NSString stringWithFormat:@"%p",self];
104 - (void)applyValue:(NSString*)value {
105     NSLog(@"Applied the value \"%@\" to an AMPurpleRequestField!", value);
108 @end
110 @implementation AMPurpleRequestFieldString
112 - (NSXMLElement*)xhtml {
113         NSXMLElement *result = [super xhtml];
114         
115         const char *defaultvalue = purple_request_field_string_get_default_value(field);
116         BOOL isMultiline = (purple_request_field_string_is_multiline(field) == TRUE) ? YES : NO;
117         BOOL isEditable = (purple_request_field_string_is_editable(field) == TRUE) ? YES : NO;
118         BOOL isMasked = (purple_request_field_string_is_masked(field) == TRUE) ? YES : NO;
119         BOOL isVisible = (purple_request_field_is_visible(field) == TRUE) ? YES : NO;
120         
121         NSXMLElement *textinput;
122         
123         if(isMultiline) {
124                 textinput = [NSXMLNode elementWithName:@"textarea"];
125                 [textinput addAttribute:[NSXMLNode attributeWithName:@"rows" stringValue:@"5"]];
126                 [textinput addAttribute:[NSXMLNode attributeWithName:@"cols" stringValue:@"40"]];
127                 if(defaultvalue)
128                         [textinput setStringValue:[NSString stringWithUTF8String:defaultvalue]];
129         } else {
130                 textinput = [NSXMLNode elementWithName:@"input"];
131                 if (isVisible)
132                         [textinput addAttribute:[NSXMLNode attributeWithName:@"type" stringValue:isMasked?@"password":@"text"]];
133                 else
134                         [textinput addAttribute:[NSXMLNode attributeWithName:@"type" stringValue:@"hidden"]];
135                 [textinput addAttribute:[NSXMLNode attributeWithName:@"size" stringValue:@"50"]];
136                 if(defaultvalue)
137                         [textinput addAttribute:[NSXMLNode attributeWithName:@"value" stringValue:[NSString stringWithUTF8String:defaultvalue]]];
138         }
139         [textinput addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
140         if(!isEditable)
141                 [textinput addAttribute:[NSXMLNode attributeWithName:@"readonly" stringValue:@"readonly"]];
143         if (isVisible)
144                 [result addChild:[NSXMLNode elementWithName:@"div"
145                                                                                    children:[NSArray arrayWithObject:textinput]
146                                                                                  attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"input"]]]];
147         else
148                 return textinput;
150     return result;
153 - (void)applyValue:(NSString*)value {
154         purple_request_field_string_set_value(field, [value UTF8String]);
157 @end
160 @implementation AMPurpleRequestFieldInteger
162 - (NSXMLElement*)xhtml {
163         NSXMLElement *result = [super xhtml];
164         
165         int defaultvalue = purple_request_field_int_get_default_value(field);
166         
167         NSXMLElement *textinput = [NSXMLNode elementWithName:@"input"];
168         [textinput addAttribute:[NSXMLNode attributeWithName:@"type" stringValue:@"text"]];
169         [textinput addAttribute:[NSXMLNode attributeWithName:@"value" stringValue:[NSString stringWithFormat:@"%d",defaultvalue]]];
170         [textinput addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
171         // XXX add javascript to make sure this is integer-only
173         [result addChild:[NSXMLNode elementWithName:@"div"
174                                                                            children:[NSArray arrayWithObject:textinput]
175                                                                          attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"input"]]]];
177     return result;
180 - (void)applyValue:(NSString*)value {
181         purple_request_field_int_set_value(field, [value intValue]);
184 @end
186 @implementation AMPurpleRequestFieldBoolean
188 - (NSXMLElement*)xhtml {
189         NSXMLElement *result = [super xhtml];
190         
191         BOOL defaultvalue = (purple_request_field_bool_get_default_value(field) == TRUE) ? YES : NO;
192         
193         NSXMLElement *checkbox = [NSXMLNode elementWithName:@"input"];
194         [checkbox addAttribute:[NSXMLNode attributeWithName:@"type" stringValue:@"checkbox"]];
195         [checkbox addAttribute:[NSXMLNode attributeWithName:@"value" stringValue:[self key]]];
196         [checkbox addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
198         if(defaultvalue)
199                 [checkbox addAttribute:[NSXMLNode attributeWithName:@"checked" stringValue:@"checked"]];
201         [result addChild:[NSXMLNode elementWithName:@"div"
202                                                                            children:[NSArray arrayWithObject:checkbox]
203                                                                          attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"input"]]]];
204         
205         purple_request_field_bool_set_value(field, FALSE); // since we won't get an -applyValue: message when the checkbox isn't checked, assume false for now. This might be changed later.
206     return result;
209 - (void)applyValue:(NSString*)value {
210         purple_request_field_bool_set_value(field, TRUE);
213 @end
215 @implementation AMPurpleRequestFieldChoice
217 - (NSXMLElement*)xhtml {
218         NSXMLElement *result = [super xhtml];
219         
220         GList *labels = purple_request_field_choice_get_labels(field);
221         
222         guint len = g_list_length(labels);
223         int defaultvalue = purple_request_field_choice_get_default_value(field);
224         
225         // Apple HIG: Don't use checkboxes for lists of more than 5 items, use a popupbutton instead
226         if(len > 5) {
227                 NSXMLElement *popup = [NSXMLNode elementWithName:@"select"];
228                 [popup addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
229                 int i=0;
230                 for(GList *label = labels; label; label = g_list_next(label), ++i) {
231                         const char *labelstr = label->data;
232                         if(!labelstr)
233                                 continue;
234                         
235                         NSXMLElement *option = [NSXMLNode elementWithName:@"option" stringValue:[NSString stringWithUTF8String:labelstr]];
236                         [option addAttribute:[NSXMLNode attributeWithName:@"value" stringValue:[NSString stringWithFormat:@"%u",i]]];
237                         if(i == defaultvalue)
238                                 [option addAttribute:[NSXMLNode attributeWithName:@"selected" stringValue:@"selected"]];
239                         [popup addChild:option];
240                 }
241                 [result addChild:[NSXMLNode elementWithName:@"div"
242                                                                                    children:[NSArray arrayWithObject:popup]
243                                                                                  attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"input"]]]];
244         } else {
245                 int i=0;
246                 NSMutableArray *radios = [NSMutableArray array];
247                 for(GList *label = labels; label; label = g_list_next(label), ++i) {
248                         const char *labelstr = label->data;
249                         if(!labelstr)
250                                 continue;
251                         
252                         NSXMLElement *radiobutton = [NSXMLNode elementWithName:@"input"];
253                         [radiobutton addAttribute:[NSXMLNode attributeWithName:@"type" stringValue:@"radio"]];
254                         [radiobutton addAttribute:[NSXMLNode attributeWithName:@"value" stringValue:[NSString stringWithFormat:@"%u",i]]];
255                         [radiobutton addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
257                         if(i == defaultvalue)
258                                 [radiobutton addAttribute:[NSXMLNode attributeWithName:@"checked" stringValue:@"checked"]];
259                         
260                         [radios addObject:radiobutton];
261                         [radios addObject:[NSXMLNode textWithStringValue:[NSString stringWithUTF8String:labelstr]]];
262                 }
263                 [result addChild:[NSXMLNode elementWithName:@"div"
264                                                                                    children:radios
265                                                                                  attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"input"]]]];
266         }
267         
268     return result;
271 - (void)applyValue:(NSString*)value {
272         purple_request_field_choice_set_value(field, [value intValue]);
275 @end
277 @implementation AMPurpleRequestFieldList
279 - (NSXMLElement*)xhtml {
280         NSXMLElement *result = [super xhtml];
281         
282         BOOL isMultiSelect = (purple_request_field_list_get_multi_select(field) == TRUE) ? YES : NO;
284         NSXMLElement *list = [NSXMLNode elementWithName:@"select"];
285         [list addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
286         
287         if(isMultiSelect)
288                 [list addAttribute:[NSXMLNode attributeWithName:@"multiple" stringValue:@"multiple"]];
290         const GList *items = purple_request_field_list_get_items(field);
291         guint len = g_list_length((GList*)items);
292         
293         // show all items up to 10
294         [list addAttribute:[NSXMLNode attributeWithName:@"size" stringValue:[NSString stringWithFormat:@"%u",(len>10)?10:len]]];
295         
296         for(const GList *item = items; item; item = g_list_next(item)) {
297                 const char *labelstr = item->data;
298                 if(!labelstr)
299                         continue;
300                 
301                 NSXMLElement *option = [NSXMLNode elementWithName:@"option" stringValue:[NSString stringWithUTF8String:labelstr]];
302                 if(purple_request_field_list_is_selected(field, labelstr))
303                         [option addAttribute:[NSXMLNode attributeWithName:@"selected" stringValue:@"selected"]];
304                 [list addChild:option];
305         }
306         [result addChild:[NSXMLNode elementWithName:@"div"
307                                                                            children:[NSArray arrayWithObject:list]
308                                                                          attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"input"]]]];
309         
310         return result;
313 - (void)applyValue:(NSString*)value {
314         purple_request_field_list_add_selected(field, [value UTF8String]);
317 @end
319 @implementation AMPurpleRequestFieldLabel
321 #if 0
322 - (NSXMLNode*)xhtml {
323     return [super xhtml];
325 #endif
327 @end
329 @implementation AMPurpleRequestFieldAccount
330 // this is not used by libpurple, so should I care about it?
331 @end
333 @implementation AMPurpleRequestFieldImage
335 - (NSXMLElement*)xhtml {
336         NSXMLElement *result = [super xhtml];
337         
338         //unsigned int scale_x = purple_request_field_image_get_scale_x(field);
339         //unsigned int scale_y = purple_request_field_image_get_scale_y(field);
340                 
341         //This could be base 64 encoded and embedded directly, but it seems like a heavy fix...
342         NSData *data = [NSData dataWithBytes:purple_request_field_image_get_buffer(field)
343                                                                   length:purple_request_field_image_get_size(field)];
344                                 
345         NSString *extension = [NSImage extensionForBitmapImageFileType:[NSImage fileTypeOfData:data]];
346         if (!extension) {
347                 //We don't know what it is; try to make a png out of it
348                 NSImage                         *image = [[NSImage alloc] initWithData:data];
349                 NSData                          *imageTIFFData = [image TIFFRepresentation];
350                 NSBitmapImageRep        *bitmapRep = [NSBitmapImageRep imageRepWithData:imageTIFFData];
351                 
352                 data = [bitmapRep representationUsingType:NSPNGFileType properties:nil];
353                 extension = @"png";
354                 [image release];
355         }
357         NSString *filename = [[[NSString stringWithFormat:@"TEMP-Image_%@",[self key]] stringByAppendingPathExtension:extension] safeFilenameString];
358         NSString *imagePath = [[[AIObject sharedAdiumInstance] cachesPath] stringByAppendingPathComponent:filename];
360         NSXMLElement *imageElement = [NSXMLNode elementWithName:@"image"];
362         if ([data writeToFile:imagePath atomically:YES]) {
363                 [imageElement addAttribute:[NSXMLNode attributeWithName:@"src" stringValue:[[NSURL fileURLWithPath:imagePath] absoluteString]]];
364                 [imageElement addAttribute:[NSXMLNode attributeWithName:@"name" stringValue:[self key]]];
366                 [result addChild:[NSXMLNode elementWithName:@"div"
367                                                                                    children:[NSArray arrayWithObject:imageElement]
368                                                                                  attributes:[NSArray arrayWithObject:[NSXMLNode attributeWithName:@"class" stringValue:@"image"]]]];            
369         } else {
370                 AILogWithSignature(@"Failed to write image to %@",imagePath);
371         }
373     return result;
377 @end
379 @implementation AMPurpleRequestFieldsController
381 - (id)initWithTitle:(NSString*)title
382         primaryText:(NSString*)primary
383       secondaryText:(NSString*)secondary
384       requestFields:(PurpleRequestFields*)_fields
385              okText:(NSString*)okText
386            callback:(GCallback)_okcb
387          cancelText:(NSString*)cancelText
388            callback:(GCallback)_cancelcb
389             account:(CBPurpleAccount*)account
390                 who:(NSString*)who
391        conversation:(PurpleConversation*)conv
392            userData:(void*)_userData {
393     if((self = [super initWithWindowNibName:@"AMPurpleRequestFieldsWindow"])) {
394         // we only need to store these fields
395         fields = _fields;
396         okcb = _okcb;
397         cancelcb = _cancelcb;
398         userData = _userData;
399         
400         // generate XHTML
401         NSXMLElement *root = [NSXMLNode elementWithName:@"html"];
402         [root addNamespace:[NSXMLNode namespaceWithName:@"" stringValue:@"http://www.w3.org/1999/xhtml"]];
403         NSXMLElement *head = [NSXMLNode elementWithName:@"head"];
404         [root addChild:head];
405         
406         [head addChild:[NSXMLNode elementWithName:@"style" children:[NSArray arrayWithObject:
407             [NSXMLNode textWithStringValue:
408                 @"body {"
409                                 @"      font-family:'Lucida Grande';"
410                                 @"      font-size: 13pt;"
411                                 @"}"
412                                 @"h1 {"
413                                 @"      display: none;"
414                                 @"}"
415                                 @"h2 {"
416                                 @"      font-size: 13pt;"
417                                 @"      font-weight: normal;"
418                                 @"}"
419                                 @"h3 {"
420                                 @"      font-size: 11pt;"
421                                 @"      font-weight: normal;"
422                                 @"}"
423                                 @"#formwrapper"
424                                 @"{"
425                                 @"      position: fixed;"
426                                 @"      top: 0px;"
427                                 @"      left: 0;"
428                                 @"      bottom: 50px;"
429                                 @"      right: 0;"
430                                 @"      overflow: auto;"
431                                 @"}"
432                                 @"#form2"
433                                 @"{"
434                                 @"      margin: 20px;"
435                                 @"      overflow: none;"
436                                 @"}"
437                                 @"#formtable"
438                                 @"{"
439                                 @"      display: table;"
440                                 @"      margin: 0 auto;"
441                                 @"}"
442                                 @".field {"
443                                 @"      position: relative;"
444                                 @"      display: table-row;"
445                                 @"      font-size: 13pt;"
446                                 @"}"
447                                 @".label {"
448                                 @"      text-align: right;"
449                                 @"      display: table-cell;"
450                                 @"      width: 50%;"
451                                 @"      padding-right: .2em;"
452                                 @"      vertical-align: top;"
453                                 @"      font-size: 13pt;"
454                                 @"}"
455                                 @".label:after {"
456                                 @"      content: \":\";"
457                                 @"}"
458                                 @".input {"
459                                 @"      display: table-cell;"
460                                 @"      width: 50%;"
461                                 @"      padding-left: .2em;"
462                                 @"      vertical-align: top;"
463                                 @"}"
464                                 @"#cancel {"
465                                 @"      font-size: 13pt;"
466                                 @"      margin-right: 10px;"
467                                 @"}"
468                                 @"#submit {"
469                                 @"      font-size: 13pt;"
470                                 @"      margin-right: 20px;"
471                                 @"      margin-left: 10px;"
472                                 @"}"
473                                 @"#submitbuttons {"
474                                 @"      text-align: right;"
475                                 @"      position: absolute;"
476                                 @"      bottom: 0;"
477                                 @"      right: 0;"
478                                 @"      overflow: auto;"
479                                 @"      height: 45px;"
480                                 @"      width: 100%;"
481                                 @"      border-color: #000;"
482                                 @"      border-width: 1px 0 0 0;"
483                                 @"      border-style: solid;"
484                                 @"}"
485                 ]] attributes:[NSArray arrayWithObject:
486                     [NSXMLNode attributeWithName:@"type" stringValue:@"text/css"]]]];
488         NSXMLElement *titleelem = [NSXMLNode elementWithName:@"title" stringValue:title];
489         [head addChild:titleelem];
491         NSXMLElement *body = [NSXMLNode elementWithName:@"body"];
492         [root addChild:body];
494         
495         NSXMLElement *formnode = [NSXMLNode elementWithName:@"form" children:nil attributes:[NSArray arrayWithObjects:
496             [NSXMLNode attributeWithName:@"action" stringValue:@"http://www.adiumx.com/XMPP/form"],
497             [NSXMLNode attributeWithName:@"method" stringValue:@"POST"],nil]];
498         [body addChild:formnode];
499                 
500                 NSXMLElement *formwrapper = [NSXMLNode elementWithName:@"div"];
501                 [formwrapper addAttribute:[NSXMLNode attributeWithName:@"id" stringValue:@"formwrapper"]];
502                 [formnode addChild:formwrapper];
503                 NSXMLElement *form2 = [NSXMLNode elementWithName:@"div"];
504                 [form2 addAttribute:[NSXMLNode attributeWithName:@"id" stringValue:@"form2"]];
505                 [formwrapper addChild:form2];
506                 
507                 formwrapper = form2;
509                 NSXMLElement *heading = [NSXMLNode elementWithName:@"h1" stringValue:title];
510         [formwrapper addChild:heading];
511                 
512         NSXMLElement *heading2 = [NSXMLNode elementWithName:@"h2" stringValue:primary];
513         [formwrapper addChild:heading2];
514                 
515         NSXMLElement *heading3 = [NSXMLNode elementWithName:@"h3" stringValue:secondary];
516         [formwrapper addChild:heading3];
517                 
518                 NSXMLElement *formdiv = [NSXMLNode elementWithName:@"div"];
519                 [formdiv addAttribute:[NSXMLNode attributeWithName:@"id" stringValue:@"formtable"]];
520                 [formwrapper addChild:formdiv];
521                 
522         // load field objects
523         
524         fieldobjects = [[NSMutableDictionary alloc] init];
525         
526         GList *gl = purple_request_fields_get_groups(fields);
527                 GList *fl, *field_list;
528                 PurpleRequestFieldGroup *group;
529         
530         NSXMLElement *fieldset;
531                 guint len = g_list_length(gl);
532         
533                 //Look through each group, processing each field and transforming it into an Objective C object
534                 for (; gl != NULL; gl = gl->next) {
535                         group = gl->data;
536                         // only display groups when there's more than one
537                         if(len > 1) {
538                                 fieldset = [NSXMLNode elementWithName:@"fieldset"];
539                                 [formdiv addChild:fieldset];
541                                 const char *fieldtitle = purple_request_field_group_get_title(group);
542                                 if(fieldtitle)
543                                         [fieldset addChild:[NSXMLNode elementWithName:@"legend" stringValue:[NSString stringWithUTF8String:fieldtitle]]];
544                         } else
545                                 fieldset = formdiv;
546                         
547                         field_list = purple_request_field_group_get_fields(group);
548                         
549                         for (fl = field_list; fl != NULL; fl = fl->next) {
550                 PurpleRequestField              *field;
551                 
552                 AMPurpleRequestField *fieldobject = nil;
554                                 field = (PurpleRequestField *)fl->data;
555                                 switch(purple_request_field_get_type(field)) {
556                     case PURPLE_REQUEST_FIELD_STRING:
557                         fieldobject = [[AMPurpleRequestFieldString alloc] initWithAccount:account requestField:field];
558                         break;
559                     case PURPLE_REQUEST_FIELD_INTEGER:
560                         fieldobject = [[AMPurpleRequestFieldInteger alloc] initWithAccount:account requestField:field];
561                         break;
562                     case PURPLE_REQUEST_FIELD_BOOLEAN:
563                         fieldobject = [[AMPurpleRequestFieldBoolean alloc] initWithAccount:account requestField:field];
564                         break;
565                     case PURPLE_REQUEST_FIELD_CHOICE:
566                         fieldobject = [[AMPurpleRequestFieldChoice alloc] initWithAccount:account requestField:field];
567                         break;
568                     case PURPLE_REQUEST_FIELD_LIST:
569                         fieldobject = [[AMPurpleRequestFieldList alloc] initWithAccount:account requestField:field];
570                         break;
571                     case PURPLE_REQUEST_FIELD_LABEL:
572                         fieldobject = [[AMPurpleRequestFieldLabel alloc] initWithAccount:account requestField:field];
573                         break;
574                                         case PURPLE_REQUEST_FIELD_IMAGE:
575                                                 fieldobject = [[AMPurpleRequestFieldImage alloc] initWithAccount:account requestField:field];
576                                                 break;
577                                                 /*
578                     case PURPLE_REQUEST_FIELD_ACCOUNT:
579                         fieldobject = [[AMPurpleRequestFieldAccount alloc] initWithAccount:account requestField:field];
580                         break;
581                                                  */
582                     default:
583                         fieldobject = nil;
584                 }
585                 if(fieldobject) {
586                     //Keep objects for later processing of the form
587                     [fieldobjects setObject:fieldobject forKey:[fieldobject key]];
589                     //Insert the field into the XHTML document
590                     [fieldset addChild:[fieldobject xhtml]];
591                     [fieldobject release];
592                 }
593             }
594         }
595         
596         [formnode addChild:[NSXMLNode elementWithName:@"div" children:[NSArray arrayWithObjects:
597 #if 0
598             [NSXMLNode elementWithName:@"input" children:nil attributes:[NSArray arrayWithObjects:
599                 [NSXMLNode attributeWithName:@"type" stringValue:@"submit"],
600                 [NSXMLNode attributeWithName:@"id" stringValue:@"cancel"],
601                 [NSXMLNode attributeWithName:@"value" stringValue:cancelText],nil]],
602 #endif
603             [NSXMLNode elementWithName:@"input" children:nil attributes:[NSArray arrayWithObjects:
604                 [NSXMLNode attributeWithName:@"type" stringValue:@"submit"],
605                 [NSXMLNode attributeWithName:@"id" stringValue:@"submit"],
606                 [NSXMLNode attributeWithName:@"value" stringValue:okText],nil]],
607                         nil] attributes:[NSArray arrayWithObject:[NSXMLElement attributeWithName:@"id" stringValue:@"submitbuttons"]]]];
608         
609         NSXMLDocument *doc = [NSXMLNode documentWithRootElement:root];
610         [doc setCharacterEncoding:@"UTF-8"];
611         [doc setDocumentContentKind:NSXMLDocumentXHTMLKind];
612         
613                 if(title)
614                         [[self window] setTitle:title];
615                 else
616                         [[self window] setTitle:AILocalizedString(@"Form","Generic fields request window title")];
617                 
618                 /*
619                  //Code here originally made the webview transparent; the result is an all-black window. I don't think this is desired.
620                 if ([webview respondsToSelector:@selector(setBackgroundColor:)]) {
621                         //As of Safari 3.0, we must call setBackgroundColor: to make the webview transparent
622                         [webview setBackgroundColor:[NSColor clearColor]];
624                 } else {
625                         [webview setDrawsBackground:NO];
626                 }
627                  */
628                  
629         [self performSelector:@selector(loadForm:) withObject:doc afterDelay:0.0];
630         
631         [[NSNotificationCenter defaultCenter] addObserver:self
632                                                  selector:@selector(webviewWindowWillClose:)
633                                                      name:NSWindowWillCloseNotification
634                                                    object:[self window]];
635     }
636     return [self retain]; // keep us as long as the form is open
639 - (void)dealloc {
640     [fieldobjects release];
642     [super dealloc];
645 - (void)loadForm:(NSXMLDocument*)doc {
646     NSData *formdata = [doc XMLDataWithOptions:NSXMLDocumentTidyHTML | NSXMLDocumentIncludeContentTypeDeclaration];
647     [[webview mainFrame] loadData:formdata MIMEType:@"application/xhtml+xml" textEncodingName:@"UTF-8" baseURL:nil];
648     [self showWindow:nil];
651 #pragma mark WebView Delegate Methods
653 - (void)webviewWindowWillClose:(NSNotification *)notification {
654     [webview setPolicyDelegate:nil];
655    
656     if (wasSubmitted) {
657         if (okcb)
658             ((PurpleRequestFieldsCb)okcb)(userData, fields);
659     } else {
660         if (cancelcb)
661             ((PurpleRequestFieldsCb)cancelcb)(userData, fields);
662     }
663     
664     [self autorelease]; // no we don't need us no longer, commit suicide
667 - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation
668                 request:(NSURLRequest *)request
669                   frame:(WebFrame *)frame
670         decisionListener:(id<WebPolicyDecisionListener>)listener
672     if ([[[request URL] scheme] isEqualToString:@"applewebdata"] || [[[request URL] scheme] isEqualToString:@"about"])
673         [listener use];
675     else {
676         if ([[[request URL] absoluteString] isEqualToString:@"http://www.adiumx.com/XMPP/form"]) {
677             NSString *info = [[NSString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding];
678             NSArray *formfields = [info componentsSeparatedByString:@"&"];
679             [info release];
680             
681             NSEnumerator *e = [formfields objectEnumerator];
682             NSString *field;
683             while ((field = [e nextObject])) {
684                 NSArray *keyvalue = [field componentsSeparatedByString:@"="];
685                 if ([keyvalue count] != 2)
686                     continue;
687                                 
688                 NSString *key = [[[keyvalue objectAtIndex:0] mutableCopy] autorelease];
689                 [(NSMutableString *)key replaceOccurrencesOfString:@"+"
690                                                                                                                 withString:@" " 
691                                                                                                                    options:NSLiteralSearch 
692                                                                                                                          range:NSMakeRange(0,[key length])];
693                 
694                 key = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
695                                                                                           (CFStringRef)key,
696                                                                                           (CFStringRef)@"", kCFStringEncodingUTF8);
697                 
698                 NSString *value = [[[keyvalue objectAtIndex:1] mutableCopy] autorelease];
699                 [(NSMutableString *)value replaceOccurrencesOfString:@"+" 
700                                                                                                                   withString:@" " 
701                                                                                                                          options:NSLiteralSearch 
702                                                                                                                            range:NSMakeRange(0,[value length])];
703                 
704                 value = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
705                                                                                             (CFStringRef)value,
706                                                                                             (CFStringRef)@"", kCFStringEncodingUTF8);
707                 
708                                 [[fieldobjects objectForKey:key] applyValue:value];
709                 
710                 [key release];
711                 [value release];
712             }
713             
714                         wasSubmitted = YES;
715             [self close];
716         }
718         [listener ignore];
719     }
722 @end